package com.ecarx.vhaltests.hy11.testcases.charging;

import static com.ecarx.xui.adaptapi.car.hev.ICharging.CHARGE_FUNC_CHARGING_PLUG_STATE;
import static com.ecarx.xui.adaptapi.car.hev.ICharging.CHARGE_PLUG_MIS_MATCHED;
import static com.ecarx.xui.adaptapi.car.hev.ICharging.CHARGE_PLUG_STATE_CONNECTED;
import static com.ecarx.xui.adaptapi.car.hev.ICharging.CHARGE_PLUG_STATE_DISCONNECTED;
import static com.ecarx.xui.adaptapi.car.hev.ICharging.CHARGE_PLUG_STATE_MULTI;
import static com.ecarx.xui.adaptapi.car.hev.ICharging.CHARGE_PLUG_STATE_NONE;
import static com.ecarx.xui.adaptapi.car.hev.ICharging.CHARGE_PLUG_STATE_QUICK_CHARGING_CONNECTED;
import static com.ecarx.xui.adaptapi.car.hev.ICharging.CHARGE_PLUG_STATE_SLOW_CHARGING_CONNECTED;
import static com.ecarx.xui.adaptapi.car.hev.ICharging.CHARGE_PLUG_STATE_WAITING;

import android.car.VehicleAreaType;
import android.car.hardware.CarPropertyValue;
import android.car.hardware.property.CarPropertyManager;

import androidx.test.platform.app.InstrumentationRegistry;

import com.ecarx.vhaltests.CallbackTimer;
import com.ecarx.vhaltests.IpcpClient;
import com.ecarx.vhaltests.VehicleConstants;
import com.ecarx.vhaltests.VhalUnitTestBase;
import com.ecarx.xui.adaptapi.car.IWrapper;

import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runners.MethodSorters;

@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class ChargeFuncChargingPlugStateTest extends VhalUnitTestBase {
    private static int propertyId;
    private static IWrapper.IPropertyId wrapperProperty;
    private CallbackTimer cbkTimer = new CallbackTimer();
    private CarPropertyManager.CarPropertyEventCallback propertyCbk;
    private static IpcpClient ipcpClient = new IpcpClient();
    private boolean isFirstCbk;
    private static final int AREA_ID = VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL;

    @BeforeClass
    public static void testInit() {
        IWrapper wrapper = com.ecarx.xui.adaptapi.car.Car.createWrapper(InstrumentationRegistry.getInstrumentation().getTargetContext());
        wrapperProperty = wrapper.getWrappedPropertyId(IWrapper.WrappedIdType.ID_TYPE_FUNCTION, CHARGE_FUNC_CHARGING_PLUG_STATE);
        propertyId = wrapperProperty.getPropertyId();
        setAvailable(true);
        Assert.assertTrue(isAvail());
    }

    @Test
    public void test001_GetChargeFuncChargingPlugStateDisconnected() {
        testGet(CHARGE_PLUG_STATE_DISCONNECTED);
    }

    @Test
    public void test002_GetChargeFuncChargingPlugStateSlowChargingConnected() {
        testGet(CHARGE_PLUG_STATE_SLOW_CHARGING_CONNECTED);
    }

    @Test
    public void test003_GetChargeFuncChargingPlugStateQuickChargingConnected() {
        testGet(CHARGE_PLUG_STATE_QUICK_CHARGING_CONNECTED);
    }

    @Test
    public void test004_GetChargeFuncChargingPlugStateConnected() {
        testGet(CHARGE_PLUG_STATE_CONNECTED);
    }

    @Test
    public void test005_GetChargeFuncChargingPlugStateWaiting() {
        testGet(CHARGE_PLUG_STATE_WAITING);
    }

    @Test
    public void test006_GetChargeFuncChargingPlugStateMulti() {
        testGet(CHARGE_PLUG_STATE_MULTI);
    }

    @Test
    public void test007_GetChargeFuncChargingPlugStateMisMatched() {
        testGet(CHARGE_PLUG_MIS_MATCHED);
    }

    @Test
    public void test008_GetChargeFuncChargingPlugStateNone() {
        testGet(CHARGE_PLUG_STATE_NONE);
    }

    @Test
    public void test009_GetChargeFuncChargingPlugStateKeepLast() {
        testGet(CHARGE_PLUG_MIS_MATCHED);
        delay();
        mockState(CHARGE_PLUG_STATE_WAITING, true);
        Assert.assertEquals(wrapperProperty.getPropertyValue(CHARGE_PLUG_MIS_MATCHED).intValue(), getValue());
    }

    @Test
    public void test010_GetChargeFuncChargingPlugStateCbk() {
        testCbk();
    }

    @Test
    public void test011_GetChargeFuncChargingPlugStateUnavail() {
        setAvailable(false);
        Assert.assertFalse(isAvail());
    }

    private void testGet(int state) {
        testGet(state, false);
    }

    private void testGet(int state, boolean isTimeout) {
        mockState(state, isTimeout);
        delay();
        int expectedValue = wrapperProperty.getPropertyValue(state);
        Assert.assertEquals(expectedValue, getValue());
    }

    private static void mockState(Integer state) {
        mockState(state, false);
    }

    private static void mockState(Integer state, boolean isTimeout) {
        setAvailable(true, state, isTimeout);
    }

    private static void setAvailable(boolean isAvail) {
        setAvailable(isAvail, null);
    }

    private static void setAvailable(boolean isAvail, Integer state) {
        setAvailable(isAvail, state, false);
    }

    private static void setAvailable(boolean isAvail, Integer state, boolean isTimeout) {
        int cemSvcId = 37;
        int[] cemOperIds = {999};

        int ccSvcId = 135;
        int[] ccOperIds = {200};
        int[] ccConfigs = {13};
        int[] ccValues = {4};

        ipcpClient.setConfig(cemSvcId, cemOperIds);
        ipcpClient.setConfig(ccSvcId, ccOperIds);

        String[] cems = {"vehModMngtGlbSafe1CarModSts1", "vehModMngtGlbSafe1UsgModSts"};
        int[] cemValues = {isAvail ? VehicleConstants.CAR_MODE_NOMAL : VehicleConstants.CAR_MODE_TRANSPORT, VehicleConstants.USG_MODE_CONVENIENCE};
        boolean cemRet = ipcpClient.setCEMSignal(cemSvcId, cemOperIds[0], cems, cemValues);
        Assert.assertTrue(cemRet);
        boolean ccRet = ipcpClient.setCarconfigSignal(ccSvcId, ccOperIds[0], ccConfigs, ccValues);
        Assert.assertTrue(ccRet);

        int timeoutSvcId = 99;
        int[] timeoutOperIds = {200};
        ipcpClient.setConfig(timeoutSvcId, timeoutOperIds);
        String[] timeoutConfigs = {"onBdChrgrHndlSts1Timeout", "dCChrgnHndlStsTimeout"};
        int[] timeoutValues = {isTimeout ? 1 : 0, isTimeout ? 1 : 0};
        boolean toRet = ipcpClient.setTimeoutSignal(timeoutSvcId, timeoutOperIds[0], timeoutConfigs, timeoutValues);
        Assert.assertTrue(toRet);

        if (state != null) {
            int vddmSvcId = 48;
            int[] vddmOperIds = {999};
            String[] vddmConfigs = null;
            int[] vddmValues = null;
            ipcpClient.setConfig(vddmSvcId, vddmOperIds);
            switch (state) {
                case CHARGE_PLUG_STATE_SLOW_CHARGING_CONNECTED:
                    vddmConfigs = new String[]{"onBdChrgrHndlSts1", "dCChrgnHndlSts"};
                    vddmValues = new int[]{1, 4};
                    break;
                case CHARGE_PLUG_STATE_CONNECTED:
                    vddmConfigs = new String[]{"onBdChrgrHndlSts1", "dCChrgnHndlSts"};
                    vddmValues = new int[]{5, 4};
                    break;
                case CHARGE_PLUG_STATE_QUICK_CHARGING_CONNECTED:
                    vddmConfigs = new String[]{"onBdChrgrHndlSts1", "dCChrgnHndlSts"};
                    vddmValues = new int[]{8, 2};
                    break;
                case CHARGE_PLUG_STATE_WAITING:
                    vddmConfigs = new String[]{"onBdChrgrHndlSts1", "dCChrgnHndlSts"};
                    vddmValues = new int[]{10, 4};
                    break;
                case CHARGE_PLUG_STATE_DISCONNECTED:
                    vddmConfigs = new String[]{"onBdChrgrHndlSts1", "dCChrgnHndlSts"};
                    vddmValues = new int[]{8, 4};
                    break;
                case CHARGE_PLUG_MIS_MATCHED:
                    vddmConfigs = new String[]{"onBdChrgrHndlSts1", "dCChrgnHndlSts"};
                    vddmValues = new int[]{9, 4};
                    break;
                case CHARGE_PLUG_STATE_MULTI:
                    boolean retCC = ipcpClient.setCarconfigSignal(ccSvcId, ccOperIds[0], new int[]{13, 29}, new int[]{4, 5});
                    Assert.assertTrue(retCC);
                    vddmConfigs = new String[]{"onBdChrgrHndlSts1", "dCChrgnHndlSts"};
                    vddmValues = new int[]{1, 2};
                    break;
                case CHARGE_PLUG_STATE_NONE:
                    // 设置前置条件NotActive
                    boolean retCEM = ipcpClient.setCEMSignal(cemSvcId, cemOperIds[0], new String[]{"vehModMngtGlbSafe1CarModSts1"}, new int[]{VehicleConstants.CAR_MODE_TRANSPORT});
                    Assert.assertTrue(retCEM);
                    break;
            }
            if (vddmConfigs != null && vddmValues != null) {
                boolean retVDDM = ipcpClient.setVDDMSignal(vddmSvcId, vddmOperIds[0], vddmConfigs, vddmValues);
                Assert.assertTrue(retVDDM);
            }
        }
    }

    private int getValue() {
        delay();
        return mCarPropertyMgr.getIntProperty(propertyId, AREA_ID);
    }

    private static boolean isAvail() {
        delay();
        return mCarPropertyMgr.isPropertyAvailable(propertyId, AREA_ID);
    }

    private void testCbk() {
        isFirstCbk = true;
        mockState(CHARGE_PLUG_MIS_MATCHED);
        delay();
        int expectedValue = wrapperProperty.getPropertyValue(CHARGE_PLUG_STATE_MULTI);
        propertyCbk = new CarPropertyManager.CarPropertyEventCallback() {
            @Override
            public void onChangeEvent(CarPropertyValue carPropertyValue) {
                if (carPropertyValue.getAreaId() == AREA_ID) {
                    if (isFirstCbk) {
                        isFirstCbk = false;
                    } else {
                        int value = (int) carPropertyValue.getValue();
                        Assert.assertEquals(expectedValue, value);
                        mCarPropertyMgr.unregisterCallback(propertyCbk);
                        cbkTimer.finish();
                    }
                }
            }

            @Override
            public void onErrorEvent(int i, int i1) {
            }
        };
        mCarPropertyMgr.registerCallback(propertyCbk, propertyId, CarPropertyManager.SENSOR_RATE_ONCHANGE);
        mockState(CHARGE_PLUG_STATE_MULTI);
        cbkTimer.start();
    }

}